package org.toves.checklua.parse;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.toves.checklua.ast.AstNode;
import org.toves.checklua.ast.AstNodeType;
import org.toves.checklua.ast.AstNodes;
import org.toves.checklua.scan.Token;
import org.toves.checklua.scan.TokenType;

class ParseStackEntry {
	private Token start;
	private AstNodeType stmtType;
	private Token reprToken;
	private Set<TokenType> ends;
	private ArrayList<Object> parms;
	private List<AstNode> block;
	
	ParseStackEntry(AstNodeType type, Token start, Token reprToken,
			Set<TokenType> ends) {
		this.stmtType = type;
		this.start = start;
		this.reprToken = reprToken;
		this.ends = ends;
		this.parms = new ArrayList<Object>();
		this.block = new ArrayList<AstNode>();
	}
	
	public Token getStartToken() {
		return start;
	}
	
	public Set<TokenType> getEndTokenTypes() {
		return ends;
	}
	
	public void addParameter(Object value) {
		parms.add(value);
	}
	
	public List<Object> getParameters() {
		return parms;
	}
	
	public void addToBlock(AstNode stmt) {
		block.add(stmt);
	}
	
	public AstNode getBlockAndClear() {
		List<AstNode> stmts = block;
		block = new ArrayList<AstNode>();
		return AstNodes.forSeq(reprToken, stmts);
	}
	
	public AstNode createNode() {
		if (stmtType == AstNode.ASSN) {
			return AstNodes.forAssn(reprToken, (List<AstNode>) parms.get(0),
					(List<AstNode>) parms.get(1));
		} else if (stmtType == AstNode.ASSN_LOCAL) {
			return AstNodes.forAssnLocal(reprToken, (List<Token>) parms.get(0),
					(List<AstNode>) parms.get(1));
		} else if (stmtType == AstNode.BREAK) {
			return AstNodes.forBreak(reprToken);
		} else if (stmtType == AstNode.CALL_AS_STMT) {
			return AstNodes.forCall(reprToken, (AstNode) parms.get(0),
					(List<AstNode>) parms.get(1));
		} else if (stmtType == AstNode.DEF_FUNC) {
			return AstNodes.forFunctionDef(reprToken, (AstNode) parms.get(0),
					(List<Token>) parms.get(1), (AstNode) parms.get(2));
		} else if (stmtType == AstNode.DEF_FUNC_LOCAL) {
			return AstNodes.forFunctionDefLocal(reprToken, (AstNode) parms.get(0),
					(List<Token>) parms.get(1), (AstNode) parms.get(2));
		} else if (stmtType == AstNode.DO) {
			return AstNodes.forDo(reprToken, (AstNode) parms.get(0));
		} else if (stmtType == AstNode.EMPTY) {
			return AstNodes.forEmpty();
		} else if (stmtType == AstNode.FOR_EACH) {
			return AstNodes.forForEach(reprToken, (List<Token>) parms.get(0),
					(List<AstNode>) parms.get(1), (AstNode) parms.get(2));
		} else if (stmtType == AstNode.FOR_INTS) {
			return AstNodes.forForInts(reprToken, (Token) parms.get(0),
					(AstNode) parms.get(1), (AstNode) parms.get(2),
					(AstNode) parms.get(3), (AstNode) parms.get(4));
		} else {
			throw new RuntimeException("Unexpected stack entry type");
		}
	}

}
